﻿using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor.Experimental.GraphView;
using UnityEngine;
using UnityEngine.Events;
using XLFrame.NodeEditor.Extensions;

namespace XLFrame.NodeEditor
{
    /// <summary>
    /// 节点逻辑相关代码
    /// </summary>
    public class NodeViewLogic
    {
        private NodeViewBase m_nodeView;
        private UnityAction<INodeLogic> m_OnExecuteEnd;
        public NodeViewLogic(NodeViewBase nodeView,UnityAction<INodeLogic> OnExecuteEnd)
        {
            m_nodeView = nodeView;
            m_OnExecuteEnd = OnExecuteEnd;
            m_nodeView.NodePort.OnRuntimePortRemoveEvent += OnRuntimePortRemove;
            m_nodeView.NodePort.OnRuntimeCreatePortEvent += OnRuntimeCreatePort;
            m_nodeView.OnNodeDataLoadingDataEndEvent += OnDataLoadingEnd;
        }

        /// <summary>
        /// 节点注册的逻辑层
        /// </summary>
        private List<INodeLogic> nodeLogics = new List<INodeLogic>();

        #region 事件

        /// <summary>
        /// [注册在 OnNodeDataLoadingDataEnd]
        /// 当前节点加载数据结束时调用 所有节点加载完成后
        /// </summary>
        protected virtual void OnDataLoadingEnd()
        {
            foreach (var item in nodeLogics)
            {
                item.Init(m_nodeView.NodeData, m_nodeView.NodePort.GetInputPortData, m_nodeView.NodePort.GetOutputPortData, OnNextExecute);
            }
        }
        
        /// <summary>
        /// [注册自OnRuntimePortRemoveEvent]
        /// 当运行时移除端口时调用
        /// </summary>
        /// <param name="obj"></param>
        private void OnRuntimePortRemove(Port obj)
        {
            // 通知逻辑层更新端口数据
            foreach (var Logic in nodeLogics)
            {
                Logic.RefreshData();
            }
        }
        
        
        /// <summary>
        /// [注册自OnRuntimeCreatePortEvent]
        /// 运行时新增端口 
        /// </summary>
        /// <param name="obj"></param>
        private void OnRuntimeCreatePort(Port obj)
        {
            // 通知逻辑层更新端口数据
            foreach (var Logic in nodeLogics)
            {
                Logic.RefreshData();
            }
        }

        #endregion
        
        /// <summary>
        /// 需要在所有端口创建完毕后调用,自动保存添加的逻辑类型
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public T AddNodeLogic<T>() where T : INodeLogic, new()
        {
            T logic = new T();

            // 读取存档时,自动添加逻辑类
            m_nodeView.NodeData.NodeLogicData.Add(typeof(T).GetTypeNameAndAssembly());
            AddNodeLogic(logic);
            return logic;
        }

        /// <summary>
        /// 添加节点逻辑,不进行保存节点逻辑类型,自动初始化
        /// </summary>
        /// <param name="logic"></param>
        public void AddNodeLogic(INodeLogic logic)
        {
            nodeLogics.Add(logic);
            logic.Init(m_nodeView.NodeData, m_nodeView.NodePort.GetInputPortData, m_nodeView.NodePort.GetOutputPortData, OnNextExecute);
            logic.OnExecuteEnd += m_OnExecuteEnd;
        }
        /// <summary>
        /// 当执行下一个节点逻辑时调用
        /// </summary>
        /// <param name="arg0"></param>
        private void OnNextExecute(string arg0)
        {
            if (!m_nodeView.NodePort.OutputPort[arg0].connections.Any())
                return;

            var inputPort = m_nodeView.NodePort.OutputPort[arg0].connections.First().input;
            var data = inputPort.node;

            if (data is NodeViewBase node)
            {
                node.NodeLogic.Execute(inputPort.portName);
            }
        }
        /// <summary>
        /// 执行节点逻辑
        /// </summary>
        public void Execute(string lineName,string EGuid="")
        {
            if (string.IsNullOrEmpty(EGuid))
            {
                EGuid = Guid.NewGuid().ToString();
            }
            string nameType = ToolExtensions.RemoveNameType(lineName);
            foreach (var logic in nodeLogics)
            {
                logic.EGuid = EGuid;
                logic.Execute(nameType);
            }
        }
    }
}